﻿using System.Collections.ObjectModel;

using Gonte.Wpf.Controls.ResourceManagers;
using Gonte.Algorithms;

namespace Gonte.Wpf.Controls.ViewModel
{
    /// <summary>
    /// The view model of object that contain children
    /// </summary>
    public class ContentViewModel
        : ItemViewModel
    {
        #region Constructors

        public ContentViewModel(ContentViewModelInfo viewModelInfo)
            : base(viewModelInfo)
        {
            if (!string.IsNullOrEmpty(viewModelInfo.Label))
            {
                _label = viewModelInfo.Label;
            }

            UpdateIconSource();
        }

        public ContentViewModel(ContentViewModelInfo viewModelInfo, bool loadOnDemand)
            : base(viewModelInfo)
        {
            if (!string.IsNullOrEmpty(viewModelInfo.Label))
            {
                _label = viewModelInfo.Label;
            }

            UpdateIconSource();

            if (viewModelInfo.LoadOnDemand)
            {
                _children.Add(LoadOnDemandViewModel.Instance);
            }
        }

        public ContentViewModel(ContentViewModelInfo viewModelInfo, ContentViewModel parent, object model)
            : base(viewModelInfo)
        {
            ExceptionThrower.ThrowWhenNull("model", model);

            _parent = parent;
            _model = model;

            if (!string.IsNullOrEmpty(viewModelInfo.Label))
            {
                _label = viewModelInfo.Label;
            }

            UpdateIconSource();

            if (viewModelInfo.LoadOnDemand)
            {
                _children.Add(LoadOnDemandViewModel.Instance);
            }
        }

        #endregion

        #region Overridables

        public virtual void LoadChildren()
        {
            PopulateChildren();
            SortChildren();
        }

        public void AddChild(ItemViewModel viewModel)
        {
            // Expand and select the added view model
            viewModel.IsExpanded = true;
            viewModel.IsSelected = true;

            _children.Add(viewModel);

            SortChildren();
        }

        public bool RemoveChild(ItemViewModel viewModel)
        {
            bool removed = _children.Remove(viewModel);

            if (!removed)
            {
                return removed;
            }

            IsSelected = true; // Select the parent
            OnPropertyChanged("Children");

            return removed;
        }

        public bool MoveChildUp(ItemViewModel item, out int newIndex)
        {
            int oldIndex = _children.IndexOf(item);
            newIndex = oldIndex - 1;

            if (oldIndex == 0)
            {
                return false; // It is the first already
            }

            _children.Move(oldIndex, newIndex);
            OnPropertyChanged("Children");

            return true;
        }

        public bool MoveChildDown(ItemViewModel item, out int newIndex)
        {
            int oldIndex = _children.IndexOf(item);
            if (oldIndex == _children.Count - 1)
            {
                newIndex = -1;
                return false; // It is the last already
            }

            newIndex = oldIndex + 1;
            _children.Move(oldIndex, newIndex);
            OnPropertyChanged("Children");

            return true;
        }

        #endregion

        #region Properties

        /// <summary>
        /// The binding to this view model
        /// </summary>
        public ReadOnlyCollection<ContentViewModel> This
        {
            get
            {
                return new ReadOnlyCollection<ContentViewModel>
                (
                    new ContentViewModel[] { this }
                );
            }
        }

        public override bool IsExpanded
        {
            get
            {
                return _isExpanded;
            }

            set
            {
                if (value != _isExpanded)
                {
                    _isExpanded = value;
                    OnPropertyChanged("IsExpanded");

                    UpdateIconSource();

                    // Needed when searching to make it visible in the control
                    if (null != _parent)
                    {
                        _parent.IsExpanded = true; // Propagate to the root
                    }

                    if (IsLoadedOnDemand)
                    {
                        Children.Remove(LoadOnDemandViewModel.Instance);
                        LoadChildren();
                    }
                }
            }
        }

        public ObservableCollection<IViewModel> Children
        {
            get { return _children; }

            set
            {
                _children = value;
                OnPropertyChanged("Children");
            }
        }
 
        #endregion

        #region Helpers

        /// <summary>
        /// Updates the image according to the state of the model info
        /// </summary>
        protected override void UpdateIconSource()
        {
            ContentViewModelInfo viewModelInfo = (ContentViewModelInfo)_viewModelInfo;
            string imageUri = null;

            if (null == _model) // Model info is empty
            {
                imageUri = viewModelInfo.EmptyIconUri;
            }
            else
            {
                if (_isExpanded)
                {
                    imageUri = viewModelInfo.ExpandedIconUri;
                }
                else
                {
                    imageUri = viewModelInfo.CollapsedIconUri;
                }
            }

            _iconSource = ImageManager.GetImage(imageUri);

            OnPropertyChanged("IconSource");
        }

        public bool IsLoadedOnDemand
        {
            get
            {
                return (_children.Count == 1
                    && _children[0] == LoadOnDemandViewModel.Instance);
            }
        }

        protected ItemViewModel FindChild(object child)
        {
            foreach (ItemViewModel viewModel in _children)
            {
                if (viewModel.Model.Equals(child))
                {
                    return viewModel;
                }
            }

            return null;
        }

        private void PopulateChildren()
        {
            if (null != AddChildren)
            {
                AddChildren(this);
            }
        }

        public void SortChildren()
        {
            ContentViewModelInfo viewModelInfo = (ContentViewModelInfo)_viewModelInfo;

            if (viewModelInfo.SortChildren)
            {
                ShellSorter<ItemViewModel>.Sort(_children);
            }

            OnPropertyChanged("Children");
        }

        #endregion

        #region Fields

        private bool _isExpanded;
        private ObservableCollection<IViewModel> _children = new ObservableCollection<IViewModel>();

        #region Add children event handlers

        public delegate void AddChildrenHandler(ContentViewModel viewModel);

        /// <summary>
        /// Called to add the children view model to this view model
        /// </summary>
        public AddChildrenHandler AddChildren;

        #endregion

        #endregion
    }
}
